`include "common_def.v"
`define MSTATUS_MIE 3
`define MSTATUS_MPIE 7
`define MIP_MTIP 7
`define MIE_MTIE 7
`define MIP_MEIP 11
`define MIE_MEIE 11
`define MIP_MSIP 3
`define MIE_MSIE 3
`define MCAUSE_ECALL 64'h0000_0000_0000_000b
`define MCAUSE_MTI 64'h8000_0000_0000_0007
`define MCAUSE_MEI 64'h8000_0000_0000_000b
`define MCAUSE_MSI 64'h8000_0000_0000_0003
module MODULE_CSRS(
	input 							clk_i,
	input 							rst_i,
	input 							wen_csr_i,
	input 	[11:0] 			addr_csr_r_i,
	input 	[11:0] 			addr_csr_w_i,
	input 	[`WIDTH-1:0]data_csr_w_i,
	input								is_ecall_i,
	input								is_mret_i,
	input 	[`WIDTH-1:0]ecall_pc_i,
	output 	[`WIDTH-1:0]data_csr_r_o,
	output 	[`WIDTH-1:0]mtvec_r_o,
	input								mtip_i,
	input								meip_i,
	input								msip_i,
	input								mintr_happen_i,
	output							interrupt_o
);
assign mtvec_r_o[`WIDTH-1:0] = mtvec_r[`WIDTH-1:0];
wire is_mti;
wire is_mei;
wire is_msi;
assign is_mti = (mip_r[`MIP_MTIP]&mie_r[`MIE_MTIE]);
assign is_mei = (mip_r[`MIP_MEIP] & mie_r[`MIE_MEIE]);
assign is_msi = (mip_r[`MIP_MSIP] & mie_r[`MIE_MSIE]);
assign interrupt_o =  mstatus_r[`MSTATUS_MIE] &(is_mti|is_mei|is_msi);
	//data_write for mepc and mcause
wire 	[`WIDTH-1:0]		mtvec_r;
wire 	[`WIDTH-1:0]		mpc_r;
wire	[`WIDTH-1:0]		mcause_r;
wire	[`WIDTH-1:0]		mstatus_r;
wire	[`WIDTH-1:0]		mip_r;
wire	[`WIDTH-1:0]		mie_r;

wire 	[`WIDTH-1:0]		mtvec_w;
wire 	[`WIDTH-1:0]		mpc_w;
wire	[`WIDTH-1:0]		mcause_w;
wire	[`WIDTH-1:0]		mstatus_w;
wire	[`WIDTH-1:0]		mip_w;
wire	[`WIDTH-1:0]		mie_w;

assign mtvec_w[`WIDTH-1:0] = data_csr_w_i[`WIDTH-1:0];
assign mcause_w[`WIDTH-1:0] = is_ecall_i ? `MCAUSE_ECALL: (mintr_happen_i&is_mei)? `MCAUSE_MEI :(mintr_happen_i&is_msi) ? `MCAUSE_MSI :  (mintr_happen_i&is_mti) ? `MCAUSE_MTI:data_csr_w_i[`WIDTH-1:0];
assign mie_w[`WIDTH-1:0] = data_csr_w_i[`WIDTH-1:0];
assign mpc_w[`WIDTH-1:0] = is_ecall_i|mintr_happen_i ? ecall_pc_i[`WIDTH-1:0]:data_csr_w_i[`WIDTH-1:0];
assign mip_w = (mtip_i|meip_i|msip_i) ? {mip_r[`WIDTH-1:`MIP_MEIP+1],meip_i,mip_r[`MIP_MEIP-1:`MIP_MTIP+1],mtip_i,mip_r[`MIP_MTIP-1:`MIP_MSIP+1],msip_i,mip_r[`MIP_MSIP-1:0]}:0;
wire [1:0] mstatus_w_key;
assign mstatus_w_key[1:0] = {is_mret_i,is_ecall_i|mintr_happen_i};
MuxKeyWithDefault #(2,2,`WIDTH) mstatus_w_mux(mstatus_w[`WIDTH-1:0],mstatus_w_key[1:0],data_csr_w_i[`WIDTH-1:0],{
	2'b01, {mstatus_r[`WIDTH-1:`MSTATUS_MPIE+1],mstatus_r[`MSTATUS_MIE],mstatus_r[`MSTATUS_MPIE-1:`MSTATUS_MIE+1],1'b0,mstatus_r[`MSTATUS_MIE-1:0]},
	2'b10, {mstatus_r[`WIDTH-1:`MSTATUS_MPIE+1],1'b1,mstatus_r[`MSTATUS_MPIE-1:`MSTATUS_MIE+1],mstatus_r[`MSTATUS_MPIE],mstatus_r[`MSTATUS_MIE-1:0]}
});


wire 									mtvec_wen;
wire 									mpc_wen;
wire									mcause_wen;
wire									mstatus_wen;
wire									mip_wen;
wire									mie_wen;
assign	mtvec_wen = wen_csr_i&(addr_csr_w_i == `MTVEC);
assign	mpc_wen =(wen_csr_i&(addr_csr_w_i == `MPC))|is_ecall_i|mintr_happen_i;
assign	mcause_wen = (wen_csr_i&(addr_csr_w_i == `MCAUSE))|is_ecall_i|mintr_happen_i;
assign	mstatus_wen = wen_csr_i&(addr_csr_w_i == `MSTATUS)|is_ecall_i|is_mret_i|mintr_happen_i;
assign	mie_wen = wen_csr_i&(addr_csr_w_i == `MIE);
assign  mip_wen = 1'b1;
Reg #(`WIDTH,0) mtvec (clk_i,rst_i,mtvec_w[`WIDTH-1:0],mtvec_r[`WIDTH-1:0],mtvec_wen);
Reg #(`WIDTH,0) mpc (clk_i,rst_i,mpc_w[`WIDTH-1:0],mpc_r[`WIDTH-1:0],mpc_wen);
Reg #(`WIDTH,0) mcause (clk_i,rst_i,mcause_w[`WIDTH-1:0],mcause_r[`WIDTH-1:0],mcause_wen);
Reg #(`WIDTH,64'h0000000a00001800) mstatus (clk_i,rst_i,mstatus_w[`WIDTH-1:0],mstatus_r[`WIDTH-1:0],mstatus_wen);
//Reg #(`WIDTH,0) mstatus (clk_i,rst_i,mstatus_w[`WIDTH-1:0],mstatus_r[`WIDTH-1:0],mstatus_wen);
Reg #(`WIDTH,0) mip(clk_i,rst_i,mip_w[`WIDTH-1:0],mip_r[`WIDTH-1:0],mip_wen);
Reg #(`WIDTH,0) mie(clk_i,rst_i,mie_w[`WIDTH-1:0],mie_r[`WIDTH-1:0],mie_wen);
MuxKey #(`CSRS_NUM,12,`WIDTH) mux_crc_r(data_csr_r_o[`WIDTH-1:0],addr_csr_r_i[11:0],{
	`MTVEC,mtvec_r[`WIDTH-1:0],	
	`MPC, mpc_r[`WIDTH-1:0],	
	`MSTATUS, mstatus_r[`WIDTH-1:0],	
	`MCAUSE, mcause_r[`WIDTH-1:0],
	`MIP,	mip_r[`WIDTH-1:0],
	`MIE,	mie_r[`WIDTH-1:0]
});
//DPI-C for simulation
wire [`WIDTH-1:0] csrs_diff_o[2:0];//delete
assign csrs_diff_o[0] = mcause_r;//delete
assign csrs_diff_o[1] = mstatus_r;//delete
assign csrs_diff_o[2] = mpc_r;//delete
import "DPI-C" function void set_csrs_ptr(input [`WIDTH-1:0] a[]);//delete
initial set_csrs_ptr(csrs_diff_o);//delete

endmodule
